package com.skilltrack.enrol.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.skilltrack.enrol.mapper.CourseBaseMapper;
import com.skilltrack.enrol.mapper.CourseCategoryMapper;
import com.skilltrack.enrol.mapper.CourseMarketMapper;
import com.skilltrack.enrol.model.dto.AddCourseDto;
import com.skilltrack.enrol.model.dto.CourseBaseInfoDto;
import com.skilltrack.enrol.model.dto.EditCourseDto;
import com.skilltrack.enrol.model.dto.QueryCourseParamsDto;
import com.skilltrack.enrol.model.po.CourseBase;
import com.skilltrack.enrol.model.po.CourseCategory;
import com.skilltrack.enrol.model.po.CourseMarket;
import com.skilltrack.enrol.service.CourseBaseInfoService;
import com.skilltrackedu.exception.exception.CommonException;
import com.skilltrackedu.model.PageParams;
import com.skilltrackedu.model.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class CourseBaseInfoServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements CourseBaseInfoService {

    @Autowired
    private CourseBaseMapper courseBaseMapper;

    @Autowired
    private CourseMarketMapper courseMarketMapper;

    @Autowired
    private CourseCategoryMapper courseCategoryMapper;

    /**
     * 查询课程基础信息列表
     *
     * @param pageParams           分页参数，包括页号和每页大小
     * @param queryCourseParamsDto 查询课程的参数，包括课程名称、审核状态和发布状态
     * @return 返回课程基础信息的分页结果
     */
    @Override
    public PageResult<CourseBase> queryCourseBaseList(PageParams pageParams, QueryCourseParamsDto queryCourseParamsDto) {

        log.info("courseBaseMapper: {}", courseBaseMapper);
        log.info("pageParams: {}", pageParams);
        log.info("queryCourseParamsDto: {}", queryCourseParamsDto);


        // 创建Lambda查询包装器，用于拼装where后面的查询条件
        LambdaQueryWrapper<CourseBase> queryWrapper = new LambdaQueryWrapper<>();

        if (queryCourseParamsDto != null) {
            // 拼装查询条件，包括课程名称、审核状态和发布状态(许判断是否为null在拼接)
            queryWrapper

                    //根据名称模糊查询,在sql中拼接 course_base.name like '%?%'
                    .like(queryCourseParamsDto.getCourseName() != null && !queryCourseParamsDto.getCourseName().isEmpty(), CourseBase::getName, queryCourseParamsDto.getCourseName())

                    // 根据审核状态查询 course_base.audit_status = ?
                    .eq(queryCourseParamsDto.getAuditStatus() != null && !queryCourseParamsDto.getAuditStatus().isEmpty(), CourseBase::getAuditStatus, queryCourseParamsDto.getAuditStatus())

                    // 根据发布状态查询 course_base.status = ?
                    .eq(queryCourseParamsDto.getPublishStatus() != null && !queryCourseParamsDto.getPublishStatus().isEmpty(), CourseBase::getStatus, queryCourseParamsDto.getPublishStatus());
        }

        // 调用Mapper方法，根据分页参数和查询条件查询课程基础信息
        Page<CourseBase> page = courseBaseMapper.selectPage(new Page<>(pageParams.getPageNo(), pageParams.getPageSize()), queryWrapper);

        // 将查询结果封装成PageResult对象并返回
        return new PageResult<>(page.getRecords(), page.getTotal(), pageParams.getPageNo(), pageParams.getPageSize());
    }

    /**
     * 新增课程基础信息
     *
     * @param companyId    所属机构ID，用于关联课程与培训机构
     * @param addCourseDto 包含课程基本信息和营销信息的传输对象
     * @return CourseBaseInfoDto 包含完整课程信息的数据传输对象（当前实现暂未封装结果）
     */
    @Transactional
    @Override
    public CourseBaseInfoDto createCourseBase(Long companyId, AddCourseDto addCourseDto) {
        // 参数合法性校验
        // 合法性校验
        /*if (StrUtil.isBlank(addCourseDto.getName())) {
            //throw new RuntimeException("课程名称为空");
            XueChengPlusException.cast("课程名称为空");
        }

        if (StrUtil.isBlank(addCourseDto.getMt())) {
            //throw new RuntimeException("课程分类为空");
            XueChengPlusException.cast("课程分类为空");
        }

        if (StrUtil.isBlank(addCourseDto.getSt())) {
            //throw new RuntimeException("课程分类为空");
            XueChengPlusException.cast("课程分类为空");
        }

        if (StrUtil.isBlank(addCourseDto.getGrade())) {
            //throw new RuntimeException("课程等级为空");
            XueChengPlusException.cast("课程等级为空");
        }

        if (StrUtil.isBlank(addCourseDto.getTeachmode())) {
            //throw new RuntimeException("教育模式为空");
            XueChengPlusException.cast("教育模式为空");
        }

        if (StrUtil.isBlank(addCourseDto.getUsers())) {
            //throw new RuntimeException("适应人群为空");
            XueChengPlusException.cast("适应人群为空");
        }

        if (StrUtil.isBlank(addCourseDto.getCharge())) {
            //throw new RuntimeException("收费规则为空");
            XueChengPlusException.cast("收费规则为空");
        }
*/
        // 向课程基本信息表course_base中插入数据
        CourseBase courseBase = BeanUtil.copyProperties(addCourseDto, CourseBase.class);

        // 设置机构id
        courseBase.setCompanyId(companyId);
        courseBase.setCreateDate(LocalDateTime.now());

        // 审核状态默认为未提交(具体值在字典表中)
        courseBase.setAuditStatus("202002");
        courseBase.setStatus("203001");

        int insert = courseBaseMapper.insert(courseBase);

        if (insert <= 0) {

            //throw new RuntimeException("新增课程失败");
            CommonException.cast("新增课程失败");
        }

        // 向课程营销信息表course_market中插入数据
        CourseMarket courseMarketNew = BeanUtil.copyProperties(addCourseDto, CourseMarket.class);

        // 主键是课程的id
        courseMarketNew.setId(courseBase.getId());

        // 调用方法保存课程营销信息
        int i = saveCourseMarket(courseMarketNew);
        if (i <= 0) {

            //throw new RuntimeException("新增课程营销信息失败");
            CommonException.cast("新增课程营销信息失败");
        }

        // 从数据库查出课程详细信息,包括两部分
        return getCourseBaseById(courseMarketNew.getId());
    }




    /**
     * 根据课程id查询课程信息
     *
     * @param courseId 课程ID，用于查询课程的基本信息和营销信息
     * @return CourseBaseInfoDto 包含完整课程信息的数据传输对象
     * 具体步骤如下：
     * 1. 根据传入的课程ID从课程基本信息表中查询CourseBase对象。
     * 2. 如果查询结果为null，则直接返回null。
     * 3. 根据相同的课程ID从课程营销信息表中查询CourseMarket对象。
     * 4. 创建CourseBaseInfoDto对象，并将CourseBase和CourseMarket的属性复制到该对象中。
     * 5. 通过courseCategoryMapper查询分类信息，获取分类名称并设置到CourseBaseInfoDto对象中。
     * （因为返回的数据中需要包含课程分类信息，所以需要根据课程ID查询对应的分类名称并封装到结果中。）
     * 6. 返回组装好的CourseBaseInfoDto对象。
     */


    public CourseBaseInfoDto getCourseBaseById(Long courseId) {

        // 从课程基本信息表查询
        CourseBase courseBase = courseBaseMapper.selectById(courseId);

        if (courseBase == null) {
            return null;
        }

        // 从课程营销信息表查询
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);

        // 组装返回
        CourseBaseInfoDto courseBaseInfoDto = new CourseBaseInfoDto();
        BeanUtils.copyProperties(courseBase, courseBaseInfoDto);

        if (courseMarket != null) {
            BeanUtils.copyProperties(courseMarket, courseBaseInfoDto);
        }

        // 通过courseCategoryMapper查询分类信息, 将分类名称赋值给courseBaseInfoDto对象
        // 因为返回的数据中需要包含课程分类信息，所以需要根据课程的分类信息查询对应的分类名称并封装到结果中。
        CourseCategory mt = courseCategoryMapper.selectById(courseBase.getMt());
        courseBaseInfoDto.setMtName(mt.getName());

        return courseBaseInfoDto;
    }


    /**
     * 更新课程基础信息
     *
     * @param companyId 课程所属的公司ID
     * @param editCourseDto 课程基础信息的DTO对象，包含要更新的课程信息
     * @return 更新后的课程基础信息DTO对象
     *
     * 该方法首先将传入的DTO对象转换为CourseBase和CourseMarket对象，
     * 然后分别更新数据库中的课程基础信息和课程营销信息如果更新失败，
     * 则抛出自定义异常表示修改课程失败
     */
    @Transactional
    @Override
    public CourseBaseInfoDto updateCourseBase(Long companyId, EditCourseDto editCourseDto) {

        //先拿到课程id进行校验
        Long courseId = editCourseDto.getId();
        //查询课程信息
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        if (courseBase == null){
            CommonException.cast("课程不存在");
        }

        // 将DTO对象转换为CourseBase对象，用于更新课程基础信息
        BeanUtil.copyProperties(editCourseDto, courseBase);
        courseBase.setChangeDate(LocalDateTime.now());

        // 将DTO对象转换为CourseMarket对象，用于更新课程营销信息
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);
        BeanUtil.copyProperties(editCourseDto, courseMarket , CopyOptions.create().setIgnoreNullValue(true));//表示如果源属性为空,则忽略该属性


        // 更新课程基础信息
        int i = courseBaseMapper.updateById(courseBase);

        // 如果更新失败，抛出异常
        if (i <= 0) {
            CommonException.cast("修改课程失败");
        }

        // 更新课程营销信息
        int j = saveCourseMarket(courseMarket);
        // 如果更新失败，抛出异常
        if (j <= 0) {
            CommonException.cast("修改课程营销信息失败");
        }

        // 返回更新后的课程基础信息
        return getCourseBaseById(courseBase.getId());
    }


    /**
     * 此方法用于新增课程时保存课程营销信息
     * 修改课程信息时,由于此代码会校验收费规则和价格.无法直接在修改课程接口中调用,因为修改接口不会传Charge
     * 单独写一个方法来保存营销信息,逻辑:存在则更新,不存在则添加
     *
     * @param courseMarket 新的课程营销信息对象，包含要保存的营销信息
     * @return 保存结果，1表示成功，0表示失败
     * @throws RuntimeException 如果收费规则为空或价格不合法，则抛出运行时异常
     */
    private int saveCourseMarket(CourseMarket courseMarket) {

        Float originalPrice = courseMarket.getOriginalPrice();

        //参数的合法性校验
        if (StrUtil.isEmpty(courseMarket.getCharge())) {

            //throw new RuntimeException("收费规则为空");
            CommonException.cast("收费规则为空");
        }

        //如果课程收费,没有填写价格也得抛异常
        if (courseMarket.getCharge().equals("201001")) {
            if ((courseMarket.getPrice() == null || courseMarket.getPrice().floatValue() <= 0)||(courseMarket.getOriginalPrice() == null || courseMarket.getOriginalPrice().floatValue() <= 0)) {

                //throw new RuntimeException("课程为收费课程,价格不能为空且必须大于0");
                CommonException.cast("课程为收费课程,价格不能为空且必须大于0");
            }
        }

        // 从数据库查询营销信息，判断是否存在该记录
        CourseMarket courseMarketTemp = courseMarketMapper.selectById(courseMarket.getId());

        if (courseMarketTemp == null) {

            // 如果记录不存在，则直接插入新记录，避免覆盖已有数据
            return courseMarketMapper.insert(courseMarket);
        } else {

            // 如果记录已存在，则需要更新而不是插入，以确保数据一致性
            // 使用BeanUtils.copyProperties进行属性值拷贝，保证只更新需要修改的部分，而不影响其他字段
            BeanUtils.copyProperties(courseMarket, courseMarketTemp);

            // 明确设置ID，确保更新操作针对正确的记录
            courseMarketTemp.setId(courseMarket.getId());

            // 执行更新操作，保持数据库中的数据与最新业务逻辑同步
            return courseMarketMapper.updateById(courseMarketTemp);
        }


    }
}
